package com.ecarx.camera.ui.camera.interior;

import static com.ecarx.camera.constant.Constants.ANIMATION_FAST_MILLIS;
import static com.ecarx.camera.constant.Constants.ANIMATION_SLOW_MILLIS;

import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.view.View;
import android.widget.Button;
import android.widget.CompoundButton;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.TextView;
import android.widget.ToggleButton;

import androidx.core.content.ContextCompat;
import androidx.core.graphics.drawable.DrawableCompat;
import androidx.fragment.app.Fragment;

import com.ecarx.camera.R;
import com.ecarx.camera.constant.Constants;
import com.ecarx.camera.ui.camera.ICameraUI;
import com.ecarx.camera.ui.contract.IMainView;
import com.ecarx.camera.utils.LogUtils;
import com.ecarx.camera.utils.ThrottleUtils;
import com.ecarx.camera.utils.Utils;
import com.ecarx.camera.worker.camera.ICameraWorker;
import com.ecarx.camera.worker.sound.SoundPlayManger;

/**
 * 内部摄像头的UI实现类
 */
public class InteriorCameraUI implements ICameraUI {

    private static final String TAG = "InteriorCameraUI";

    private static final int RECORD_BTN_ENABLE_DELAY = 600;

    private ICameraWorker mCameraWorker;

    private IMainView mMainView;
    private Fragment mFragment;

    private View mView;

    private View mVideoRecordingIndicatorLay;
    private TextView[] mDayNightFgColorTvs;
    private TextView mVideoRecordingTimeTxt;
    private ToggleButton mZoomToggleBtn;
    private RadioGroup mSwitchModesRadioGroup;
    private RadioButton mPhotoModeRadioBtn;
    private RadioButton mVideoModeRadioBtn;
    private Button mTakePhotoBtn;
    private ToggleButton mUsePhotoTimerCountdownBtn;
    private ToggleButton mRecordVideoBtn;
    private ToggleButton mUseVideoTimelapseModeBtn;
    private ToggleButton mMuteVideoBtn;
    private TextView mCountdownTxt;
    private View mNormalBottomLay;

    private boolean isZoomSupported = false;

    private boolean isCaptureInProgress = false;

    private final ThrottleUtils mThrottleUtils = new ThrottleUtils();
    private final Runnable mUpdateThumbnailWorker = new Runnable() {
        @Override
        public void run() {
            if (mMainView != null && mCameraWorker != null) {
                mMainView.setGalleryThumbnail(mCameraWorker.getLatestThumbnail());
            }
        }
    };

    /**
     * 录制按钮状态切换监听
     */
    private final CompoundButton.OnCheckedChangeListener mRecordOnCheckedChangeListener = new CompoundButton.OnCheckedChangeListener() {
        @Override
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
            if (mCameraWorker == null) {
                return;
            }
            mRecordVideoBtn.removeCallbacks(mSetRecordBtnEnableRunnable);
            setVideoRecordingButtonEnable(false);
            if (isChecked) {
                mCameraWorker.startRecordVideo();
            } else {
                mCameraWorker.stopRecordVideo();
            }
            mMuteVideoBtn.setEnabled(!isChecked);
            mUseVideoTimelapseModeBtn.setEnabled(!isChecked);
        }
    };

    /**
     * 设置录制按钮可用状态的Runnable
     */
    private final Runnable mSetRecordBtnEnableRunnable = new Runnable() {
        @Override
        public void run() {
            setVideoRecordingButtonEnable(true);
        }
    };

    @Override
    public void init(IMainView mainView, Fragment fragment) {
        mMainView = mainView;
        mFragment = fragment;
    }

    @Override
    public void bindViews(View view) {
        this.mView = view;

        mVideoRecordingIndicatorLay = view.findViewById(R.id.layout_video_recording);
        mVideoRecordingTimeTxt = view.findViewById(R.id.tv_video_recording_time);
        mZoomToggleBtn = view.findViewById(R.id.tbtn_zoom);
        mSwitchModesRadioGroup = view.findViewById(R.id.rg_switch_modes);
        mPhotoModeRadioBtn = view.findViewById(R.id.rbtn_switch_to_photo_mode);
        mVideoModeRadioBtn = view.findViewById(R.id.rbtn_switch_to_video_mode);
        mUsePhotoTimerCountdownBtn = view.findViewById(R.id.tbtn_use_photo_timer_countdown);
        mTakePhotoBtn = view.findViewById(R.id.btn_take_photo);
        mRecordVideoBtn = view.findViewById(R.id.tbtn_record_video);
        mUseVideoTimelapseModeBtn = view.findViewById(R.id.tbtn_use_video_timelapse_mode);
        mMuteVideoBtn = view.findViewById(R.id.tbtn_mute_video);
        mCountdownTxt = view.findViewById(R.id.tv_countdown);
        mNormalBottomLay = view.findViewById(R.id.lay_camera_normal_bottom);

        mDayNightFgColorTvs = new TextView[] {
                view.findViewById(R.id.tv_video_recording_tip),
                mVideoRecordingTimeTxt,
                mZoomToggleBtn,
                mUsePhotoTimerCountdownBtn,
                mTakePhotoBtn,
                mRecordVideoBtn,
                mMuteVideoBtn,
                mCountdownTxt
        };

        mZoomToggleBtn.setOnCheckedChangeListener((buttonView, isChecked) -> {
            if (buttonView.isPressed()) {
                float zoomRatio = isChecked ? Constants.MAX_ZOOM_RATIO : Constants.MIN_ZOOM_RATIO;
                if (mCameraWorker != null) {
                    mCameraWorker.setCameraZoom(zoomRatio);
                }
            }
        });
        {
            int drawableTopWidth = Utils.getApp().getResources().getDimensionPixelSize(R.dimen.camera_tbtn_drawable_top_width);
            Drawable drawableTop = ContextCompat.getDrawable(Utils.getApp(), R.drawable.camera_ic_zoom);
            drawableTop.setBounds(0, 0, drawableTopWidth, Utils.getApp().getResources().getDimensionPixelSize(R.dimen.camera_tbtn_drawable_top_height));
            mZoomToggleBtn.setCompoundDrawablesRelative(null, drawableTop, null, null);
        }
        mSwitchModesRadioGroup.setOnCheckedChangeListener((group, checkedId) -> {
            if (mCameraWorker != null) {
                mCameraWorker.setVideoMode(checkedId == mVideoModeRadioBtn.getId());
            }
        });
        {
            int drawableTopWidth = Utils.getApp().getResources().getDimensionPixelSize(R.dimen.camera_tbtn_drawable_top_width);
            Drawable drawableTop = ContextCompat.getDrawable(Utils.getApp(), R.drawable.camera_ic_mode_photo);
            drawableTop.setBounds(0, 0, drawableTopWidth, Utils.getApp().getResources().getDimensionPixelSize(R.dimen.camera_tbtn_drawable_top_height));
            mPhotoModeRadioBtn.setCompoundDrawablesRelative(null, drawableTop, null, null);
        }
        {
            int drawableTopWidth = Utils.getApp().getResources().getDimensionPixelSize(R.dimen.camera_tbtn_drawable_top_width);
            Drawable drawableTop = ContextCompat.getDrawable(Utils.getApp(), R.drawable.camera_ic_mode_video);
            drawableTop.setBounds(0, 0, drawableTopWidth, Utils.getApp().getResources().getDimensionPixelSize(R.dimen.camera_tbtn_drawable_top_height));
            mVideoModeRadioBtn.setCompoundDrawablesRelative(null, drawableTop, null, null);
        }
        mTakePhotoBtn.setOnClickListener(v -> {
            if (mCameraWorker != null) {
                mCameraWorker.doCapture();
            }
        });
        mUsePhotoTimerCountdownBtn.setOnCheckedChangeListener((buttonView, isChecked) -> {
            if (mCameraWorker != null) {
                mCameraWorker.setUsePhotoTimerCountdown(isChecked);
            }
        });
        mRecordVideoBtn.setOnCheckedChangeListener(mRecordOnCheckedChangeListener);
        mUseVideoTimelapseModeBtn.setOnCheckedChangeListener((buttonView, isChecked) -> {
            if (mCameraWorker != null) {
                mCameraWorker.setUseVideoTimelapseMode(isChecked);
            }
        });
        mMuteVideoBtn.setOnCheckedChangeListener((buttonView, isChecked) -> {
            boolean result = mCameraWorker != null && mCameraWorker.setCameraAudioMuted(isChecked);
            if (!result) {
                buttonView.setChecked(!isChecked);
            }
        });
    }

    @Override
    public void bindWorker(ICameraWorker cameraWorker) {
        mCameraWorker = cameraWorker;
    }

    @Override
    public void updateViewsWhenConfigureChanged() {
        mVideoRecordingIndicatorLay.setBackgroundColor(ContextCompat.getColor(Utils.getApp(), R.color.camera_video_recording_lay_bg_color));
        for (TextView tv : mDayNightFgColorTvs) {
            tv.setTextColor(ContextCompat.getColorStateList(Utils.getApp(), R.color.camera_btn_txt_color));
        }
        for (int index = 0; index < mSwitchModesRadioGroup.getChildCount(); index++) {
            View childView = mSwitchModesRadioGroup.getChildAt(index);
            if (childView instanceof RadioButton) {
                DrawableCompat.setTintList(((RadioButton) childView).getCompoundDrawablesRelative()[1], ContextCompat.getColorStateList(Utils.getApp(), R.color.camera_base_day_night_fg_color));
                ((RadioButton) childView).setTextColor(ContextCompat.getColor(Utils.getApp(), R.color.camera_base_day_night_fg_color));
            }
        }
        mUseVideoTimelapseModeBtn.setTextColor(ContextCompat.getColorStateList(Utils.getApp(), R.color.camera_btn_txt_color));
    }

    @Override
    public void updateOnPhotoTakingStarted() {
        LogUtils.d(TAG, "capture-> updateOnPhotoTakingStarted");
        isCaptureInProgress = true;
        showCountDownLay(false);
        // Display flash animation to indicate that photo was captured
        mView.postDelayed((Runnable) () -> {
            mView.setForeground(new ColorDrawable(Color.WHITE));
            mView.postDelayed((Runnable) () ->
                    mView.setForeground(null), ANIMATION_FAST_MILLIS);
        }, ANIMATION_SLOW_MILLIS);
    }

    @Override
    public void updateOnPictureTaken(boolean successful) {
        LogUtils.d(TAG, "capture-> updateOnPictureTaken successful:" + successful);
        isCaptureInProgress = false;
        showZoomButton(true);
        showSwitchModeLay(true);
        updateWhenPhotoModeChecked();

        if (successful) {
            LogUtils.d(TAG, "thumbnail-> updateOnPictureTaken");
            SoundPlayManger.get().playShootSound();
            updateLatestThumbnail();
        }
    }

    @Override
    public void updateOnVideoRecordingStarted() {
        showCountDownLay(false);
        showVideoRecordingIndicator(true);
        mRecordVideoBtn.postDelayed(mSetRecordBtnEnableRunnable, RECORD_BTN_ENABLE_DELAY);
        showZoomButton(true);
        showSwitchModeLay(false);
        updateWhenVideoModeChecked();
    }

    @Override
    public void updateOnVideoTaken(boolean successful) {
        LogUtils.d(TAG, "updateOnVideoTaken " + successful);
        showVideoRecordingIndicator(false);
        mRecordVideoBtn.postDelayed(mSetRecordBtnEnableRunnable, RECORD_BTN_ENABLE_DELAY);
        showZoomButton(true);
        showSwitchModeLay(true);
        updateVideoRecordingButton(false);

        if (successful) {
            LogUtils.d(TAG, "thumbnail-> updateOnVideoTaken");
            updateLatestThumbnail();
        }
    }

    @Override
    public void updateByZoomSupported(boolean isSupported) {
        LogUtils.d(TAG, "updateByZoomSupported isSupported:" + isSupported);
        isZoomSupported = isSupported;
    }

    @Override
    public void showVideoRecordingIndicator(boolean isVisible) {
        mVideoRecordingIndicatorLay.setVisibility(isVisible ? View.VISIBLE : View.GONE);
    }

    @Override
    public void setVideoRecordingTimeText(String hours, String minutes, String seconds) {
        String videoRecordingTime = Utils.getApp().getString(R.string.camera_tv_video_recording_time_text, hours, minutes, seconds);
        mVideoRecordingTimeTxt.setText(videoRecordingTime);
    }

    @Override
    public void toggleSwitchModeLay() {
        if (mCountdownTxt != null && mCountdownTxt.getVisibility() == View.VISIBLE) {
            LogUtils.d("toggleSwitchModeLay, but countdown txt is shown");
            return;
        }
        if (isCaptureInProgress) {
            LogUtils.d("toggleSwitchModeLay, but isCaptureInProgress");
            return;
        }
        if (!mRecordVideoBtn.isEnabled()) {
            LogUtils.d("toggleSwitchModeLay, but recordVideoBtn is not enabled");
            return;
        }

        if (mSwitchModesRadioGroup.getVisibility() == View.VISIBLE) {
            showZoomButton(false);
            showSwitchModeLay(false);
        } else {
            showZoomButton(true);
            showSwitchModeLay(true);
        }
    }

    @Override
    public void showSwitchModeLay(boolean isVisible) {
        mSwitchModesRadioGroup.setVisibility(isVisible ? View.VISIBLE : View.GONE);
    }

    @Override
    public void showZoomButton(boolean isVisible) {
        if (isZoomSupported) {
            mZoomToggleBtn.setVisibility(isVisible ? View.VISIBLE : View.GONE);
        } else {
            mZoomToggleBtn.setVisibility(View.GONE);
        }
    }

    @Override
    public void setZoomButtonChecked(boolean isChecked) {
        mZoomToggleBtn.setChecked(isChecked);
    }

    @Override
    public void setZoomButtonText(float zoomRatio) {
        mZoomToggleBtn.setText(Utils.getApp().getString(R.string.camera_tbtn_zoom_text, String.valueOf((int) zoomRatio)));
    }

    @Override
    public void updateWhenPhotoModeChecked() {
        mPhotoModeRadioBtn.setChecked(true);

        mTakePhotoBtn.setVisibility(View.VISIBLE);
        mUsePhotoTimerCountdownBtn.setVisibility(View.VISIBLE);
        mRecordVideoBtn.setVisibility(View.GONE);
        mUseVideoTimelapseModeBtn.setVisibility(View.GONE);
        mMuteVideoBtn.setVisibility(View.GONE);

        updateVideoRecordingButton(false);
        if (mCameraWorker != null) {
            mCameraWorker.stopRecordVideo();
        }
        mCountdownTxt.setVisibility(View.GONE);
    }

    @Override
    public void updateWhenVideoModeChecked() {
        mVideoModeRadioBtn.setChecked(true);

        mTakePhotoBtn.setVisibility(View.GONE);
        mUsePhotoTimerCountdownBtn.setVisibility(View.GONE);
        mRecordVideoBtn.setVisibility(View.VISIBLE);
        mUseVideoTimelapseModeBtn.setVisibility(View.VISIBLE);
        mMuteVideoBtn.setVisibility(View.VISIBLE);

        mUseVideoTimelapseModeBtn.setEnabled(!mRecordVideoBtn.isChecked());
        mMuteVideoBtn.setEnabled(!mRecordVideoBtn.isChecked());
        mCountdownTxt.setVisibility(View.GONE);
    }

    @Override
    public void updateVideoRecordingButton(boolean isTakingVideo) {
        mRecordVideoBtn.setChecked(isTakingVideo);
        mMuteVideoBtn.setEnabled(!isTakingVideo);
        mUseVideoTimelapseModeBtn.setEnabled(!isTakingVideo);
    }

    @Override
    public boolean updateLatestThumbnail() {
        if (mMainView == null || mCameraWorker == null) {
            return false;
        }
        mThrottleUtils.handle(mUpdateThumbnailWorker);
        return true;
    }

    @Override
    public void setVideoRecordingButtonEnable(boolean isEnable) {
        mRecordVideoBtn.setEnabled(isEnable);
    }

    @Override
    public void setPhotoTimerChecked(boolean isChecked) {
        mUsePhotoTimerCountdownBtn.setChecked(isChecked);
    }

    @Override
    public void setVideoTimelapseChecked(boolean isChecked) {
        mUseVideoTimelapseModeBtn.setChecked(isChecked);
    }

    @Override
    public void setVideoMutedChecked(boolean isChecked) {
        mMuteVideoBtn.setChecked(isChecked);
    }

    @Override
    public void showCountDownLay(boolean isVisible) {
        if (isVisible) {
            mCountdownTxt.setVisibility(View.VISIBLE);
            mNormalBottomLay.setVisibility(View.GONE);
        } else {
            mCountdownTxt.setVisibility(View.GONE);
            mNormalBottomLay.setVisibility(View.VISIBLE);
        }
    }

    @Override
    public void setCountDownText(String text) {
        mCountdownTxt.setText(text == null ? "" : text);
    }

    @Override
    public void showErrorLay(String errorText) {
        // do nothing
    }

    @Override
    public void hideErrorLay() {
        // do nothing
    }

    @Override
    public Fragment getFragment() {
        return mFragment;
    }

    @Override
    public void showAll(boolean isVisible) {
        if (mView != null) {
            mView.setVisibility(isVisible ? View.VISIBLE : View.GONE);
        }
    }
}
